﻿using DataProcess.Core.Model.Tqms;
using DataProcess.Interface;
using DataProcess.Interface.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;

namespace DataTransmission.OpcUa
{
    public class DataTransmission : BaseDataTransmission
    {
        protected override string TransmissionMark
        {
            get
            {
                return $"OpcUa";
            }
        }

        OpcUaClient opcUaClient;

        public DataTransmission(Config config) : base(config)
        {
            TransMissonConfig = config;
            opcUaClient = new OpcUaClient();
        }

        protected override Tuple<bool, string> SendData(TransferDataItem transDataItem)
        {
            if (transDataItem == null)
            {
                return new Tuple<bool, string>(false, $"传入数据为null");
            }

            if (transDataItem.Middle == null)
            {
                return new Tuple<bool, string>(false, $"过程处理数据为null");
            }

            var config = (Config)TransMissonConfig;
            if (config == null)
            {
                return new Tuple<bool, string>(false, $"{PreFix}加载Config失败");
            }

            try
            {
                string content = GetJsonContent(transDataItem);

                if (string.IsNullOrEmpty(content)) return new Tuple<bool, string>(false, "要传输的为空");

                switch (transDataItem.Middle.InstrumentType)
                {
                    case InstrumentType.XRF:
                    case InstrumentType.XRD:
                        SendXRayData(content, config);
                        break;
                    case InstrumentType.Calorimetry:
                    case InstrumentType.Analyzer:

                        break;
                    default:
                        break;
                }

                return new Tuple<bool, string>(true, string.Empty);
            }
            catch (Exception ex)
            {
                return new Tuple<bool, string>(false, ex.Message);
            }

        }

        private void SendXRayData(string content, Config config)
        {
            Dictionary<string, object> TagValuePairs = new Dictionary<string, object>();
            switch (TransMissonConfig.TransmissionDataFormat)
            {
                case TransmissionDataFormat.ProcessedData:
                    TqmsXrfOutputModel tqmsDto = content.FromJson<TqmsXrfOutputModel>();
                    if (tqmsDto == null) return;
                    foreach (var item in tqmsDto.ygyResultDetails)
                    {
                        if (float.TryParse(item.conc, out float result))
                        {
                            TagValuePairs.Add(item.compName, result);
                        }
                    }
                    break;
                case TransmissionDataFormat.MiddleData:
                    XRayOutputModel model = content.FromJson<XRayOutputModel>();
                    if (model == null) return;
                    foreach (var ele in model.Eelements)
                    {
                        if (float.TryParse(ele.Value, out float result))
                        {
                            TagValuePairs.Add(ele.Key, result);
                        }
                    }
                    break;
                case TransmissionDataFormat.RawData:
                default:
                    break;
            }

            //是否需要增加额外的通知项
            bool ok = true;
            if (!opcUaClient.IsConnected)
            {
                var task = opcUaClient.ConnectServer(config.ServerName);
                task.Wait();
                ok = task.IsCompleted;
            }
            if (ok)
            {
                //向标签中写入值
                opcUaClient.WriteNodes(TagValuePairs.Keys.ToArray(), TagValuePairs.Values.ToArray());
            }
        }
    }

    public class Config : IDataTransmissionConfig
    {
        [Display(Name = "显示名称")]
        public string Name { get; set; }

        /// <summary>
        /// 是否向HttpEndpoint发送数据
        /// </summary>
        [Display(Name = "是否启用")]
        public bool Enabled { get; set; }

        /// <summary>
        /// 传输数据的格式
        /// </summary>
        [Display(Name = "传输数据格式")]
        public TransmissionDataFormat TransmissionDataFormat { get; set; } = TransmissionDataFormat.MiddleData;

        /// <summary>
        /// 服务器
        /// </summary>
        [Display(Name = "服务器(*)")]
        [Required(ErrorMessage = "[服务器]必须填写")]
        public string ServerName { get; set; }

        /// <summary>
        /// 波特率
        /// </summary>
        [Display(Name = "命名空间(*)")]
        [Required(ErrorMessage = "[命名空间]必须填写")]
        public ushort NameSpace { get; set; } = 2;

        /// <summary>
        /// 标签所在组名
        /// </summary>
        [Display(Name = "标签所在组名称")]
        public string GroupName { get; set; }

        /// <summary>
        /// 失败重试发送。如果为False，那么发送失败数据也不会保存。
        /// </summary>
        [Display(Name = "失败重试发送")]
        [Description("如果为False，那么发送失败数据也不会保存。")]
        public bool ReTry { get; set; }

        [Display(Name = "完全失败数据是否保留")]

        public bool FaultDataRetention { get; set; }

        /// <summary>
        /// 重试次数。如果为0，那么每隔重试间隔时间，就尝试一次，直至成功。为其他数字则每隔重试间隔时间，就尝试一次，如果在重试次数耗尽还未传输成功，那么会将该条记录从发送失败表中删除不再传输。
        /// </summary>
        [Display(Name = "重试次数")]
        [Description("如果为0，那么每隔重试间隔时间，就尝试一次，直至成功。为其他数字则每隔重试间隔时间，就尝试一次，如果在重试次数耗尽还未传输成功，那么会将该条记录从发送失败表中删除不再传输。")]
        public int ReTryCount { get; set; } = 0;

        [Display(Name = "重试间隔(秒)")]
        [Range(60, 86400, ErrorMessage = "重试间隔(秒)必须在60-86400之间")]
        public int ReTyrInterval { get; set; } = 600;

        [Display(AutoGenerateField = false)]
        public string Message { get; set; }

        /// <summary>
        /// 判断此配置是否已经在指定的列表中
        /// </summary>
        /// <param name="collecion">指定的列表</param>
        /// <returns>是否已经存在</returns>
        public bool BeIncluded(IList<IDataTransmissionConfig> collecion, ref int index)
        {
            for (int i = 0; i < collecion.Count; i++)
            {
                if (collecion[i].ToString() == ToString())
                {
                    index = i + 1;
                    return true;
                }
            }
            return false;
        }

        public bool Valided()
        {
            if (string.IsNullOrEmpty(ServerName))
            {
                Message = "[端口号]不能为空";
                return false;
            }
            return true;
        }

        public override string ToString()
        {
            return ServerName;
        }
    }
}
